package org.luxor.cloud.authentication.service.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.luxor.cloud.authentication.entity.OauthClientDetailsEntity;
import org.luxor.cloud.authentication.mapper.OauthClientDetailsMapper;
import org.luxor.cloud.authentication.mapper.OauthClientResourceRefMapper;
import org.luxor.commons.core.utils.FastJsonUtils;
import org.luxor.commons.security.config.WebSecurityProperties;
import org.luxor.commons.security.entity.ClientSubject;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * OAuth2客户端详情服务
 *
 * @author Mr.Yan  @date: 2020/10/21
 */
@Primary
@Service
public class ClientDetailsServiceImpl implements ClientDetailsService {

    private Cache<String, ClientDetails> clientDetailsCache = CacheBuilder.newBuilder().expireAfterAccess(15, TimeUnit.SECONDS).build();

    @Resource
    private WebSecurityProperties webSecurityProperties;
    @Resource
    private OauthClientDetailsMapper oauthClientDetailsMapper;
    @Resource
    private OauthClientResourceRefMapper oauthClientResourceRefMapper;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        try {
            return clientDetailsCache.get(clientId, () -> {
                // 获取客户端详情
                OauthClientDetailsEntity clientDetails = oauthClientDetailsMapper.selectClientDetails(clientId);
                if (clientDetails == null) {
                    throw new NoSuchClientException("No client with requested id: " + clientId);
                }

                // 获取客户端可访问的服务提供方列表
                List<String> resourceList = oauthClientResourceRefMapper.selectResourceIds(clientId);
                // 获取客户端的额外信息
                Map<String, Object> additionalInformation = FastJsonUtils.toMap(clientDetails.getAdditionalInformation());

                String resourceIds = StringUtils.collectionToCommaDelimitedString(resourceList);
                String scopes = clientDetails.getScope();
                String grantTypes = clientDetails.getAuthorizedGrantTypes();
                String authorities = clientDetails.getAuthorities();
                String redirectUris = clientDetails.getWebServerRedirectUri();
                String autoApproveScopes = clientDetails.getAutoApprove();

                ClientSubject details = new ClientSubject(clientId, resourceIds, scopes, grantTypes, authorities, redirectUris, autoApproveScopes);
                details.setClientSecret(passwordEncoder.encode(clientDetails.getClientSecret()));
                details.setAccessTokenValiditySeconds(webSecurityProperties.getAccessTokenValiditySeconds());
                details.setRefreshTokenValiditySeconds(webSecurityProperties.getRefreshTokenValiditySeconds());
                details.setAdditionalInformation(additionalInformation);
                return details;
            });
        } catch (ExecutionException e) {
            throw new ClientRegistrationException("loadClientByClientId for [" + clientId + "]. error", e.getCause());
        }
    }

}
